package com.ctshk.rpc.payment.utils.mastercard;

import com.ctshk.rpc.payment.dto.MasterCardPayConfig;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author hef
 */
public class ApiRequestService {

    private static final Logger logger = LoggerFactory.getLogger(ApiRequestService.class);

    /**
     * Constructs API endpoint to create a new session
     *
     * @param config contains frequently used information like Merchant ID, API password, etc.
     * @return url
     */
    public static String getSessionRequestUrl(MasterCardPayConfig config) {
        return config.getGatewayHost() + "/api/rest/version/" + config.getApiVersion() + "/merchant/" + config.getMerchantId() + "/session";
    }


    public static String getOrderRequestUrl(MasterCardPayConfig config,
                                            String orderNumber, String transactionId) {
        String url = config.getGatewayHost() + "/api/rest/version/" +
                config.getApiVersion() + "/merchant/" + config.getMerchantId() + "/order/" + orderNumber;
        if (StringUtils.isNotBlank(transactionId)) {
            url += "/transaction/" + transactionId;
        }
        return url;
    }

    /**
     * Constructs API endpoint
     *
     * @param config
     * @param orderNumber
     * @return
     */
    public static String getOrderRequestUrl(MasterCardPayConfig config, String orderNumber) {
        return getOrderRequestUrl(config, orderNumber, null);
    }


    /**
     * Constructs the API payload based on properties of ApiRequest
     *
     * @param request contains info on what data the payload should include (order ID, amount, currency, etc) depending on the operation (PAY, AUTHORIZE, CAPTURE, etc)
     * @return JSON string
     */
    public static String buildJSONPayload(ApiRequest request) {

        JsonObject secureId = new JsonObject();
        if (StringUtils.isNotEmpty(request.getPaymentAuthResponse())) {
            // Used for 3DS Process ACS Result operation
            secureId.addProperty("paRes", request.getPaymentAuthResponse());
        }

        JsonObject authenticationRedirect = new JsonObject();
        // Used for 3DS check enrollment operation
        if (StringUtils.isNotEmpty(request.getSecureIdResponseUrl())) {
            authenticationRedirect.addProperty("responseUrl", request.getSecureIdResponseUrl());
            authenticationRedirect.addProperty("pageGenerationMode", "CUSTOMIZED");
            secureId.add("authenticationRedirect", authenticationRedirect);
        }

        // Used for hosted checkout - CREATE_CHECKOUT_SESSION operation
        JsonObject order = new JsonObject();
        if (StringUtils.isNotEmpty(request.getApiOperation()) && request.getApiOperation().equals("CREATE_CHECKOUT_SESSION")) {
            // Need to add order ID in the request body only for CREATE_CHECKOUT_SESSION. Its presence in the body will cause an error for the other operations.
            if (StringUtils.isNotEmpty(request.getOrderId())) order.addProperty("id", request.getOrderId());
        }
        if (StringUtils.isNotEmpty(request.getOrderAmount())) order.addProperty("amount", request.getOrderAmount());
        if (StringUtils.isNotEmpty(request.getOrderCurrency())) order.addProperty("currency", request.getOrderCurrency());
        if (StringUtils.isNotEmpty(request.getOrderNotificationUrl())) order.addProperty("notificationUrl", request.getOrderNotificationUrl());


        JsonObject wallet = new JsonObject();

        if (StringUtils.isNotEmpty(request.getWalletProvider())) {
            order.addProperty("walletProvider", request.getWalletProvider());
            // Used for Masterpass operations
            if (request.getWalletProvider().equals("MASTERPASS_ONLINE")) {
                JsonObject masterpass = new JsonObject();
                if (StringUtils.isNotEmpty(request.getMasterpassOriginUrl())) masterpass.addProperty("originUrl", request.getMasterpassOriginUrl());
                if (StringUtils.isNotEmpty(request.getMasterpassOauthToken())) masterpass.addProperty("oauthToken", request.getMasterpassOauthToken());
                if (StringUtils.isNotEmpty(request.getMasterpassOauthVerifier())) masterpass.addProperty("oauthVerifier", request.getMasterpassOauthVerifier());
                if (StringUtils.isNotEmpty(request.getMasterpassCheckoutUrl())) masterpass.addProperty("checkoutUrl", request.getMasterpassCheckoutUrl());
                if (!masterpass.entrySet().isEmpty()) wallet.add("masterpass", masterpass);
            }
        }


        JsonObject transaction = new JsonObject();
        if (StringUtils.isNotEmpty(request.getTransactionAmount()))
            transaction.addProperty("amount", request.getTransactionAmount());
        if (StringUtils.isNotEmpty(request.getTransactionCurrency()))
            transaction.addProperty("currency", request.getTransactionCurrency());
        if (StringUtils.isNotEmpty(request.getTargetTransactionId()))
            transaction.addProperty("targetTransactionId", request.getTargetTransactionId());

        JsonObject expiry = new JsonObject();
        if (StringUtils.isNotEmpty(request.getExpiryMonth())) expiry.addProperty("month", request.getExpiryMonth());
        if (StringUtils.isNotEmpty(request.getExpiryYear())) expiry.addProperty("year", request.getExpiryYear());

        JsonObject card = new JsonObject();
        if (StringUtils.isNotEmpty(request.getSecurityCode())) card.addProperty("securityCode", request.getSecurityCode());
        if (StringUtils.isNotEmpty(request.getCardNumber())) card.addProperty("number", request.getCardNumber());
        if (!expiry.entrySet().isEmpty()) card.add("expiry", expiry);

        JsonObject provided = new JsonObject();
        if (!card.entrySet().isEmpty()) provided.add("card", card);

        JsonObject sourceOfFunds = new JsonObject();
        if (StringUtils.isNotEmpty(request.getSourceType())) sourceOfFunds.addProperty("type", request.getSourceType());
        if (StringUtils.isNotEmpty(request.getSourceToken())) sourceOfFunds.addProperty("token", request.getSourceToken());
        if (!provided.entrySet().isEmpty()) sourceOfFunds.add("provided", provided);

        JsonObject browserPayment = new JsonObject();

        if (StringUtils.isNotEmpty(request.getBrowserPaymentOperation()))
            browserPayment.addProperty("operation", request.getBrowserPaymentOperation());

        if (StringUtils.isNotEmpty(request.getSourceType()) && request.getSourceType().equals("PAYPAL")) {
            JsonObject paypal = new JsonObject();
            paypal.addProperty("paymentConfirmation", "CONFIRM_AT_PROVIDER");
            browserPayment.add("paypal", paypal);
        }


        JsonObject interaction = new JsonObject();
        if (StringUtils.isNotEmpty(request.getReturnUrl()) && StringUtils.isNotEmpty(request.getApiOperation())) {
            // Return URL needs to be added differently for browser payments and hosted checkout payments
            if (request.getApiOperation().equals("CREATE_CHECKOUT_SESSION")) {
                interaction.addProperty("returnUrl", request.getReturnUrl());
            } else if (request.getApiOperation().equals("INITIATE_BROWSER_PAYMENT") || request.getApiOperation().equals("CONFIRM_BROWSER_PAYMENT")) {
                browserPayment.addProperty("returnUrl", request.getReturnUrl());
            }
        }

        JsonObject session = new JsonObject();
        if (StringUtils.isNotEmpty(request.getSessionId())) session.addProperty("id", request.getSessionId());

        // Add all the elements to the main JSON object we'll return from this method
        JsonObject data = new JsonObject();
        if (StringUtils.isNotEmpty(request.getApiOperation())) data.addProperty("apiOperation", request.getApiOperation());
        if (StringUtils.isNotEmpty(request.getSecureId())) data.addProperty("3DSecureId", request.getSecureId());
        if (!order.entrySet().isEmpty()) data.add("order", order);
        if (!wallet.entrySet().isEmpty()) data.add("wallet", wallet);
        if (!transaction.entrySet().isEmpty()) data.add("transaction", transaction);
        if (!sourceOfFunds.entrySet().isEmpty()) data.add("sourceOfFunds", sourceOfFunds);
        if (!browserPayment.entrySet().isEmpty()) data.add("browserPayment", browserPayment);
        if (!interaction.entrySet().isEmpty()) data.add("interaction", interaction);
        if (!session.entrySet().isEmpty()) data.add("session", session);
        if (!secureId.entrySet().isEmpty()) data.add("3DSecure", secureId);

        Gson gson = new GsonBuilder().setPrettyPrinting().create();

        return gson.toJson(data);
    }

    private static void throwUnsupportedProtocolException() {
        throw new IllegalArgumentException("Unsupported API protocol!");
    }
}
